#include "SceneManager.h"
#include "MeshManager.h"
#include "RegisterData.h"
#include "Root.h"

namespace DreamEngine
{

CSceneManager::CSceneManager(CRenderSystem* pRenderSytem):
m_pRenderSystem(pRenderSytem)
{

}


CSceneManager::~CSceneManager(void)
{
	MovableObjectLst::iterator moveableIter;
	for (moveableIter=m_movableLsts.begin(); moveableIter!=m_movableLsts.end(); ++moveableIter)
	{
		SAFE_DELETE(*moveableIter);
	}

	CameraLst::iterator camerasIter;
	for (camerasIter=m_cameras.begin(); camerasIter!=m_cameras.end(); ++camerasIter)
	{
		SAFE_DELETE(*camerasIter);
	}

	CNode::NodeLst::iterator iter;
	for (iter=m_nodes.begin(); iter!=m_nodes.end(); ++iter)
	{
		SAFE_DELETE(*iter);
	}
}

CSceneNode* CSceneManager::CreateSceneNode(const CString& name)
{
	CSceneNode* pNode = new CSceneNode(name);
	m_nodes.push_back(pNode);
	return pNode;
}

CCamera* CSceneManager::CreateCamera(const CString& name, CFrustum::ProjectionType type/* =CFrustum::PT_PERSPECTIVE */)
{
	CCamera* pCamera = new CCamera(name, this, type);
	if (pCamera != NULL)
	{
		m_cameras.push_back(pCamera);
	}
	return pCamera;
}

CCamera* CSceneManager::GetCamera(const CString& name)const
{
	for (CameraLst::const_iterator iter=m_cameras.begin(); iter!=m_cameras.end(); ++iter)
	{
		if ((*iter)->GetName()==name)
		{
			return (*iter);
		}
	}

	return MATH_NULL;
}

CCamera* CSceneManager::GetCamera(m_uint8 index)const
{
	if (index<m_uint8(m_cameras.size()))
	{
		return m_cameras[index];
	}

	return MATH_NULL;
}

CEntity* CSceneManager::CreateEntity(const CString& name, const CString& fileName)
{
	CMesh* pMesh = CMeshManager::InstancePtr()->CreateFromFile(name, fileName);

	CEntity* pEntity = new CEntity(m_pRenderSystem, name);
	pEntity->AddMesh(pMesh);

	pEntity->OnCreate();

	m_movableLsts.push_back(pEntity);

	return pEntity;
}


CTerrain* CSceneManager::CreateTerrain(const CString& name, 
									   const CString& highMap, 
									   int sectionSqrtCount)
{
	CTerrain* pTerrain = new CTerrain(name, m_pRenderSystem);
	pTerrain->Build(highMap, sectionSqrtCount);

	pTerrain->OnCreate();
	m_movableLsts.push_back(pTerrain);

	return pTerrain;
}

void CSceneManager::OnRender()
{
	MovableObjectLst::iterator objIter;
	for (objIter=m_movableLsts.begin(); objIter!=m_movableLsts.end(); ++objIter)
	{
		//(*iter)->OnRender();
		const CMovableObject::RenderDataLst& renderData = (*objIter)->GetRenderData();
		CMovableObject::RenderDataLst::const_iterator iter;
		for (iter=renderData.begin(); iter!=renderData.end(); ++iter)
		{
			_UpdateRegisterData(*iter, *objIter);
			m_pRenderSystem->Render(*iter);
		}
	}
}

void CSceneManager::OnLostDevice()
{
	MovableObjectLst::iterator iter;
	for (iter=m_movableLsts.begin(); iter!=m_movableLsts.end(); ++iter)
	{
		(*iter)->OnLostDevice();
	}
}

void CSceneManager::OnResetDevice()
{
	MovableObjectLst::iterator iter;
	for (iter=m_movableLsts.begin(); iter!=m_movableLsts.end(); ++iter)
	{
		(*iter)->OnResetDevice();
	}
}

void CSceneManager::OnDestory()
{
	MovableObjectLst::iterator iter;
	for (iter=m_movableLsts.begin(); iter!=m_movableLsts.end(); ++iter)
	{
		(*iter)->OnDestroy();
	}
}

int CSceneManager::GetTriangleCount()const
{
	int triangleCount = 0;
	MovableObjectLst::const_iterator iter;
	for (iter=m_movableLsts.begin(); iter!=m_movableLsts.end(); ++iter)
	{
		triangleCount += (*iter)->GetNumFace();
	}
	return triangleCount;
}

void CSceneManager::_UpdateRegisterData(const CRenderData* pRenderData,
										const CMovableObject* pObjOwner)
{
	if (pRenderData==MATH_NULL || pObjOwner==MATH_NULL) return;

	CRenderWindow* pActiveRenderWindow = CRoot::InstancePtr()->GetRenderSystem()->GetActiveRenderWindow();

	CRegisterData::InstancePtr()->SetCurMaterial(pRenderData->m_pMaterial);
	CRegisterData::InstancePtr()->SetWorldMatirx(&pObjOwner->GetWorldTransform());
	CRegisterData::InstancePtr()->SetViewMatrix(&pActiveRenderWindow->GetCamera()->GetViewMatrix());
	CRegisterData::InstancePtr()->SetCameraPosition(&pActiveRenderWindow->GetCamera()->GetPosition());		

	CMatrix16 viewProjMat;
	pActiveRenderWindow->GetCamera()->GetViewProjMatrix(viewProjMat);
	const CMatrix16& worldMat = pObjOwner->GetWorldTransform();
	CRegisterData::InstancePtr()->SetWorldViewProjMatrix(worldMat*viewProjMat);
}

}
